package cn.wdm.basic.service.impl;

import cn.wdm.basic.constants.BaseConstant;
import cn.wdm.basic.dto.RegisterDto;
import cn.wdm.basic.exception.BusinesExceprion;
import cn.wdm.basic.service.IVerifyCodeService;
import cn.wdm.basic.util.*;
import cn.wdm.user.domain.User;
import cn.wdm.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.concurrent.TimeUnit;
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Override
    public String verifyCode(String key) {
        if (!StringUtils.hasLength(key)) {
            throw new BusinesExceprion("UUID不能为空！");
        }
        //随机生成4位数
        String string = StrUtils.getRandomString(4);
        //将生成的数存入redis缓存中
        redisTemplate.opsForValue().set(key,string,5, TimeUnit.MINUTES);
        //将文字转为base64编码的字符串
        return VerifyCodeUtils.VerifyCode(100,40,string);
    }

    /**
     *获取短信验证码，需要校验图形验证码
     * @param dto
     */
    @Override
    public void getSmsCode(RegisterDto dto) {
        String phone = dto.getPhone();//点段填写的电话号码
        String codeKey = dto.getImageCodeKey();//前端的图片存的的UUID
        String codeValue = dto.getImageCodeValue();//前端输入框的图片验证码值
        //        1.参数非空校验
        if (StringUtils.isEmpty(phone)||StringUtils.isEmpty(codeKey)||StringUtils.isEmpty(codeValue)) {
            throw new BusinesExceprion("你输入的参数为空");   
        }
//        2.图片验证码校验
//            2.1校验错误抛异常
//            2.2校验正确王下走
        //在redis中根据图片验证码的key，去获取图片验证码
        //图片验证码不区分大小写
        //获取图片验证码
        Object imgValue = redisTemplate.opsForValue().get(codeKey);
        //图片验证码不相等 抛异常
        if (!imgValue.toString().equalsIgnoreCase(codeValue)) {
            throw new BusinesExceprion("验证码输入错误！");
        }
//        3.电话号码是否注册过
        User user=userMapper.loadByPhone(phone);
//            3.1注册过 提示已经注册
        if (user != null) {
            throw new BusinesExceprion("账户已经注册，请直接登录");
        }
//            3.2没有注册过继续往下走
//        4.发送短信逻辑
//            4.1根据手机号 拼接key，然后根据key获取曾将可能存在的短信验证码 register:1838
        String smsKey= BaseConstant.RegisterConstants.REGISTER_SMS_PREFIX +phone;


        //查询redis中是否之前存在短信验证码
        Object smsValue = redisTemplate.opsForValue().get(smsKey);//9523:4684654946165
        if (smsValue!=null) {
            Long oldTime = Long.valueOf(smsValue.toString().split(":")[1]);
            //如果redis中的短信验证码不为空
                //1.判断获取时间是不是小于一分钟，如果小于一分钟说明跳过前端，直接访问接口。恶意攻击
            if (System.currentTimeMillis()-oldTime<6000) {
                throw new BusinesExceprion("就你攻击我是吧！");
            }
            //验证码
            //2.超过了一分钟获取验证码，就用之间的那个验证码，重新设置过期时间和时间戳
            String str = smsValue.toString().split(":")[0];
            String strTem=str+":"+System.currentTimeMillis();//9523:468468486469866
            redisTemplate.opsForValue().set(smsKey,strTem,3,TimeUnit.MINUTES);
            System.out.println("亲，您的验证码是：" + str + "。请在3分钟内使用！！");
        }else{
            //获取随机4位验证码
            String smsCode = StrUtils.getComplexRandomString(4);//9523
            String strTem=smsCode+":"+System.currentTimeMillis();//9523:468468486469866
            redisTemplate.opsForValue().set(smsKey,strTem,3,TimeUnit.MINUTES);
            System.out.println("亲，您的验证码是：" + smsCode + "。请在3分钟内使用！！");
        }

//                4.1.1获取到了短信验证码 根据key在redis中获取value 有
//                    1.查看是否到一分钟 小于一分钟 抛出恶意攻击异常
//                                       大于一分钟，说明是再次申请了验证码 重新刷新key的过期时间，然后重新拼接时间错
//                4.1.2没有获取到短信验证码
//                    就生成验证码然后拼接新的时间戳

    }
    
    /**
     * 获取邮箱的图片验证码
     * @param dto
     */
    @Override
    public void getEmailCode(RegisterDto dto) {
        //你输入的邮箱
        String email = dto.getEmail();
        //你的图片验证码的UUID，需要去拿redis中的图片验证码
        String imageCodeKey = dto.getImageCodeKey();
        //你你输入的图片验证码
        String imageCodeValue = dto.getImageCodeValue();
        //1.非空校验
        if (StringUtils.isEmpty(email)||StringUtils.isEmpty(imageCodeKey)||StringUtils.isEmpty(imageCodeValue)) {
            throw new BusinesExceprion("内容不能为空！");
        }
        //2.图片验证码校验
            //2.1获取redis中的图片验证码
        Object imgValueInRedis = redisTemplate.opsForValue().get(imageCodeKey);
            //2.2两个图形验证码value比对
        if (!imageCodeValue.equalsIgnoreCase(imgValueInRedis.toString())) {
            throw new BusinesExceprion("图形验证码输入错误！");
        }
        //3.邮箱是否注册校验
        User user=userMapper.loadByEmail(email);
        if (user != null) {
            throw new BusinesExceprion("用户已经注册过！");
        }
        //4.发送邮件
            //4.1 判断是否是第一次请求还是第二次获取验证码
        String emailInRedisKey=BaseConstant.RegisterConstants.REGISTER_SMS_PREFIX+email;//register:1@qq.com
        Object emailInRedisValue = redisTemplate.opsForValue().get(emailInRedisKey);//1110:494964964
        //如果不为空说明是第二次
        String randomCode="";
        if (emailInRedisValue!=null) {
            String oldTime = emailInRedisValue.toString().split(":")[1];
            if (System.currentTimeMillis()-Long.valueOf(oldTime)<6000) {
                throw new BusinesExceprion("就你还攻击我！");
            }
            //超过一分钟 用之前的验证码 重新刷新时间
            String oldCode = emailInRedisValue.toString().split(":")[0];
            randomCode=oldCode+":"+System.currentTimeMillis();
        }else {//否者为一次请求游戏那个验证码 或者之间的验证码过期
            randomCode = StrUtils.getComplexRandomString(4);
        }
        //生成随机码 发送邮件
        redisTemplate.opsForValue().set(emailInRedisKey,randomCode,3,TimeUnit.MINUTES);
        SendEmailUtils.sendEmail("1756024408@qq.com","1756024408@qq.com","注册邮箱测试","你的随机码为"+randomCode);
        System.out.println("你的验证码是："+randomCode);
    }
/*========================================*/
    //共有的
    /**
     * 发送短信
      * @param smsKey
     */
    private void sendEms(String smsKey){
        //查询redis中是否之前存在短信验证码
        Object smsValue = redisTemplate.opsForValue().get(smsKey);//9523:4684654946165
        if (smsValue!=null) {
            Long oldTime = Long.valueOf(smsValue.toString().split(":")[1]);
            //如果redis中的短信验证码不为空
            //1.判断获取时间是不是小于一分钟，如果小于一分钟说明跳过前端，直接访问接口。恶意攻击
            if (System.currentTimeMillis()-oldTime<6000) {
                throw new BusinesExceprion("就你攻击我是吧！");
            }
            //验证码
            //2.超过了一分钟获取验证码，就用之间的那个验证码，重新设置过期时间和时间戳
            String str = smsValue.toString().split(":")[0];
            String strTem=str+":"+System.currentTimeMillis();//9523:468468486469866
            redisTemplate.opsForValue().set(smsKey,strTem,3,TimeUnit.MINUTES);
            System.out.println("亲，您的验证码是：" + str + "。请在3分钟内使用！！");
        }else{
            //获取随机4位验证码
            String smsCode = StrUtils.getComplexRandomString(4);//9523
            String strTem=smsCode+":"+System.currentTimeMillis();//9523:468468486469866
            redisTemplate.opsForValue().set(smsKey,strTem,3,TimeUnit.MINUTES);
            System.out.println("亲，您的验证码是：" + smsCode + "。请在3分钟内使用！！");
        }
    }
/*======================================================================================*/

    /**
     * 注册的获取短信验证码
     * @param dto
     */
    private void registerEmsCode(RegisterDto dto){
        String phone = dto.getPhone();//点段填写的电话号码
        String codeKey = dto.getImageCodeKey();//前端的图片存的的UUID
        String codeValue = dto.getImageCodeValue();//前端输入框的图片验证码值
        //        1.参数非空校验
        if (StringUtils.isEmpty(phone)||StringUtils.isEmpty(codeKey)||StringUtils.isEmpty(codeValue)) {
            throw new BusinesExceprion("你输入的参数为空");
        }
//        2.图片验证码校验
//            2.1校验错误抛异常
//            2.2校验正确王下走
        //在redis中根据图片验证码的key，去获取图片验证码
        //图片验证码不区分大小写
        //获取图片验证码
        Object imgValue = redisTemplate.opsForValue().get(codeKey);
        //图片验证码不相等 抛异常
        if (!imgValue.toString().equalsIgnoreCase(codeValue)) {
            throw new BusinesExceprion("验证码输入错误！");
        }
//        3.电话号码是否注册过
        User user=userMapper.loadByPhone(phone);
//            3.1注册过 提示已经注册
        if (user != null) {
            throw new BusinesExceprion("账户已经注册，请直接登录");
        }
//            3.2没有注册过继续往下走
//        4.发送短信逻辑
//            4.1根据手机号 拼接key，然后根据key获取曾将可能存在的短信验证码 register:1838
        String smsKey= BaseConstant.RegisterConstants.REGISTER_SMS_PREFIX +phone;
        sendEms(smsKey);
    }
/*====================================================================*/

    /**
     * 绑定生成的验证码
     * @param dto
     */
    private void bindEmsCode(RegisterDto dto){
        String smsKey="bind"+dto.getPhone();
        sendEms(smsKey);
    }

}
